import React, { useState, useEffect, useRef } from 'react';
import { Tree, Input, Empty, message, Spin } from 'antd';

import styles from './index.module.sass';

const { Search } = Input;

/**树形数据的数据源 */
export interface OriginData {
    /** 当前节点标识(key、id) */
    id: string | number,

    /** 父节点标识(key、id) */
    parentId: string | number,

    /** 当前节点展示字段 */
    name: string,
}

/**树形控件的树形数据 */
export interface TreeData {
    /** 当前节点展示字段 */
    title: string;

    /** 当前节点标识(key、id) */
    key: string;

    /** 当前节点是否为叶子节点 */
    isLeaf?: boolean;

    /**当前节点是否可选中 */
    selectable?: boolean;

    /** 当前节点的子节点 */
    children?: TreeData[];
}

/**
 * 动态往树形数据中添加子节点数据
 * @param list 当前使用的树形数据
 * @param key 要添加子节点的父节点key
 * @param children 要设置的子节点数据
 * @returns 返回已经添加好子节点的树形数据
 */
function updateTreeData(list: TreeData[], key: React.Key, children: TreeData[]): TreeData[] {
    return list.map(node => {
        if (node.key === key) {
            // 展开节点没有子节点时，设置为叶子节点
            if (_.isEmpty(children)) {
                node.isLeaf = true;
            }
            return { ...node, children };
        }
        if (node.children) {
            return {
                ...node,
                children: updateTreeData(node.children, key, children),
            };
        }
        return node;
    });
}

/**
 * 获取初始化时展开的第一个叶子节点
 * @param data 树形数据
 * @param parentId 用于查找对应的父节点信息
 * @returns 需要展开的节点列表
 */
function initExpandList(data: any, parentId?: any) {
    let expendList: string[] = [];
    (function main(_data: any) {
        for (let index = 0; index < _data.length; index++) {
            const { key, value, children } = _data[index];
            if (children) {
                main(children);
            }
            // 当传入parentId时，使用id向上获取所有的parentId
            if (parentId) {
                if (
                    key === parentId || value === parentId ||
                    expendList.find((item: any) => item === parentId)
                ) {
                    expendList.push(key || value);
                    break;
                }
            } else {
                expendList.push(key || value);
                break;
            }
        }
    }(data))
    return expendList;
}

/**
 * 从数据源中找到所有匹配上搜索内容的节点及父级节点
 * @param info 搜索内容
 * @param data 数据源
 * @param key 搜索 key 值，默认针对 name 搜索
 * @returns 匹配上搜索内容的节点及父级节点列表
 */
function getRelevantNodeData(info: any, data: OriginData[], key?: string) {
    // 获取数据源中匹配上的数据列表
    const _data = _.cloneDeep(data);
    let searchList: OriginData[] = _data.filter((item: any) => item[key ? key : 'name'].indexOf(info) > -1);
    if (key) {
        searchList = _data.filter((item: any) => item[key] === info);
    } else {
        searchList = _data.filter(({ name }: any) => name.indexOf(info) > -1);
    }

    // 获取匹配列表的父级节点
    (function main(matchList: OriginData[], originData: OriginData[]) {
        const list: OriginData[] = [...matchList];
        matchList.forEach(({ parentId }: any) => {
            originData.forEach((item: OriginData) => {
                if (parentId === item.id && list.indexOf(item) === -1) {
                    list.push(item);
                }
            })
        })
        // 没有新增数据时，结束递归
        if (list.length !== matchList.length) {
            main(list, originData);
        } else {
            searchList = list;
        }
    })(searchList, _data)

    return searchList;
}

/**
 * 只对树形数据的叶子节点进行搜索内容的筛选
 * @param data 树形数据
 * @param searchStr 搜索内容
 * @returns 筛选后的树形数据
 */
function searchLeafNode(data: any, searchStr: any) {
    return data.map((item: any) => {
        const { children, title } = item;
        if (children) {
            const _children = searchLeafNode(children, searchStr)
                // 筛选掉为空的数据
                .filter((_item: any) => !_.isEmpty(_item));
            if (_children.length > 0) {
                item.children = _children
                return item;
            } else {
                return undefined
            }
        }
        return title.indexOf(searchStr) > -1 ? item : undefined;
    })
}

/**
 * 根据搜索内容筛选树形数据
 * @param treeData 树形数据的数据源
 * @param searchStr 搜索内容
 * @returns 筛选后的树形数据
 */
function filterTreeData(treeData: TreeData[], searchStr: string) {
    const data = searchLeafNode(_.cloneDeep(treeData), searchStr);
    return data.every((item: any) => !_.isEmpty(item)) ? data : treeData;
}

interface Props {
    /**后端数据请求函数 */
    remote: Function

    /**搜索框的提示信息 */
    placeholder?: string

    /**树节点的触发事件 */
    onSelect?: Function

    /**是否不进行后端请求 */
    isNotRequest?: boolean

    /**是否不默认选中第一项可选数据 */
    isNotSelect?: boolean

    /**是否隐藏搜索框*/
    isShow?: boolean

    /**节点时候显示图标 */
    isShowIcon?: boolean
}

const DynamicLoadTree: React.FC<Props> = ({
    remote,
    placeholder,
    onSelect,
    isNotRequest,
    isNotSelect,
    isShow,
    isShowIcon
}) => {
    console.debug('DynamicLoadTree', remote);

    /**供树形控件使用的树形数据 */
    const [treeData, setTreeData] = useState<TreeData[]>([]);
    /**树形数据的数据源 */
    const [treeOriginData, setTreeOriginData] = useState<TreeData[]>([]);
    /**树形数据的数据源 */
    const [originData, setOriginData] = useState<OriginData[]>([]);
    /**需要展开的节点列表 */
    const [expandedKeys, setExpandedKeys] = useState<any>([]);
    /**当前选中的节点列表 */
    const [selectedKeys, setSelectedKeys] = useState<string[] | number[]>([]);
    /**搜索框中输入的搜索内容 */
    const [searchInfo, setSearchInfo] = useState('');
    /**展示树形控件或无数据空状态的判断依据 */
    const [showTreeNode, setShowTreeNode] = useState(true);

    const [treeHeight, setTreeHeight] = useState(100);
    const [loading, setLoading] = useState(true);
    const [firstSelect, setFirstSelect] = useState({});

    const treeRef = useRef<any>();

    useEffect(() => {
        console.log('获取数据');
        (async function () {
            if (remote) {
                try {
                    const [_treeData, _originData]: any = await remote();
                    setLoading(false);
                    if (_treeData && _originData) {
                        setTreeOriginData(_treeData);
                        setOriginData(_originData);
                        let expandList = [];
                        if (!isNotSelect) {
                            const leafNode = _originData.find((({ selectable, isLeaf }: any) => selectable || isLeaf));
                            // 判断是否有可选数据，没有就展开树形数据源的第一个节点
                            if (leafNode) {
                                const { parentId, id } = _originData[0];
                                expandList = initExpandList(_treeData, parentId);
                                setExpandedKeys(expandList);
                                setSelectedKeys([id]);
                                setFirstSelect(_originData[0]);
                            } else {
                                message.error('树形控件中没有可选数据');
                                expandList = initExpandList(_treeData);
                                setExpandedKeys(expandList);
                            }
                        } else {
                            expandList = initExpandList(_treeData).slice(1);
                            setExpandedKeys(expandList);
                        }
                    }
                } catch (error) {
                    console.error('动态选择树数据加载异常', error);
                    message.error('动态选择树数据加载异常');
                }
            }
        })()
    }, [remote, isNotSelect])

    useEffect(() => {
        if (!_.isEmpty(firstSelect)) {
            onSelect && onSelect(firstSelect);
            setFirstSelect({});
        }
    }, [firstSelect, onSelect])

    useEffect(() => {
        if (!loading) {
            if (searchInfo) {
                setTreeData(filterTreeData(treeOriginData, searchInfo));
            } else {
                setTreeData(treeOriginData);
            }
            treeRef && setTreeHeight(treeRef.current.clientHeight);
        }
    }, [treeOriginData, searchInfo, loading])

    /**
     * 在数据源中搜索当前节点下的子节点数据
     * @param key 当前展开节点的标识(key、id) 
     * @param children 当前节点下的子节点
     * @returns Promise 用于动态添加
     */
    const handleLoadData = ({ key, children }: any) => {
        return new Promise<void>(resolve => {
            if (children) {
                resolve();
                return;
            }
            const childrenData = originData.filter(({ parentId, name }: OriginData) => {
                return parentId === key;
            }).map((item: any) => {
                const { id, value, name, title } = item;
                return {
                    ..._.omit(item, ['id', 'value', 'name', 'title']),
                    key: id || value,
                    title: name || title
                };
            })
            setTreeOriginData(origin => updateTreeData(origin, key, childrenData));
            resolve();
        });
    }

    function handleSelect(selectedKeys: any, evt: any) {
        setSelectedKeys(selectedKeys);
        // 节点选中时，只展开选中节点的父节点
        // const nodeData = getRelevantNodeData(selectedKeys[0], originData, 'id');
        // const parentIdList = nodeData.map(({ id }: OriginData) => id);
        // if (!_.isEmpty(parentIdList)) {
        //     setTreeData(treeOriginData);
        //     setExpandedKeys(parentIdList);
        // }
        // 返回选中节点的完整数据及节点元素
        for (let i = 0; i < originData.length; i++) {
            if (originData[i].id === selectedKeys[0]) {
                onSelect && onSelect(originData[i], evt);
                break
            }
        }
    }

    function handleExpand(value: any) {
        setExpandedKeys(value);
    };

    function handleSearch(value?: any, event?: any) {
        const matchList = getRelevantNodeData(value, originData);
        // 匹配出的数据与数据源相同时(空白查找)，保持上一次节点展开状态。
        if (matchList.length !== originData.length && value !== searchInfo) {
            const matchParentIdList = matchList.map(({ parentId }: OriginData) => parentId);
            const expandKeyList = Array.from(new Set(matchParentIdList));
            // 进行搜索后先用树形的数据源添加子节点，再根据搜索内容筛选数据。
            if (expandKeyList.length > 0) {
                setTreeData(treeOriginData);
                setExpandedKeys(expandKeyList);
                setShowTreeNode(true);
            } else {
                setShowTreeNode(false);
            }
        } else {
            setShowTreeNode(true);
        }
        setSearchInfo(value);
    }

    return (
        <article className={styles.wrapper}>
            <header className={styles.header}>
                {!isShow && <Search
                    placeholder={placeholder}
                    onSearch={handleSearch}
                />
                }
            </header>
            {loading ? <Spin /> :
                <div className={styles.tree} ref={treeRef}>
                    {
                        showTreeNode ?
                            <Tree
                                showIcon={isShowIcon}
                                loadData={handleLoadData}
                                treeData={treeData}
                                expandedKeys={expandedKeys}
                                selectedKeys={selectedKeys}
                                onSelect={handleSelect}
                                onExpand={handleExpand}
                                height={treeHeight}
                            /> :
                            <div>
                                <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
                            </div>
                    }
                </div>
            }
        </article>
    );
};

export default DynamicLoadTree;
